package linke.study.spring.aop;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * Spring AOP在处理没实现接口的类时，
 * 会借用cglib（有接口的类是用的JDK的动态代理）来创建其代理，但是cglib只能调用无参数的构造函数
 * 来创建“代理子类”
 */
@Aspect
public class LogAspect {

	Log log = LogFactory.getLog(LogAspect.class);

	@Before("execution(* *..*Service.*(..))")
	public void serviceLog(JoinPoint joinPoint) {
		StringBuilder sbuilder = new StringBuilder();
		sbuilder.append("service layer Before Advice log: about to invoke [" + joinPoint.getSignature() + "]\n");
		Object[] args = joinPoint.getArgs();
		for (int i = 0; i < args.length; i++) {
			Object arg = args[i];
			sbuilder.append("\targ" + i + ": ");
			if (arg != null) {
				sbuilder.append("[type - ").append(arg.getClass() + "] [toString() - ").append(arg.toString()).append(']');
			} else {
				sbuilder.append("[null]");
			}
			sbuilder.append('\n');
		}
		log.info(sbuilder.toString());
	}

	@Before("execution(* *..dao..*(..))")
	public void daoLog(JoinPoint joinPoint) {
		// log.info("dao log, before " + joinPoint.getSignature());
	}

	// invoked when method returned normally
	@AfterReturning(pointcut = "execution(* *..dao..SecurityDao.*Login(..))", returning = "retVal")
	public void recordLoginResult(JoinPoint joinPoint, Object retVal) {
		log.info("securityDao AfterReturning Advice log: [" + joinPoint.getSignature() + "] returned: " + retVal);
	}

	// invoked when method returned exceptionally
	@AfterThrowing(pointcut = "within(*..dao..*)", throwing = "ex")
	public void logException(JoinPoint joinPoint, Exception ex) {
		log.error("dao exception occured in [" + joinPoint.getSignature() + "]: ", ex);
	}

	@After("within(*..service.*)")
	public void afterServiceMethod(JoinPoint joinPoint) {
		log.info("service layer After Advice log, remote request calling:" + joinPoint.getSignature() + " is dealed~\n");
	}

	/**
	 * Around advice is declared using the @Around annotation. The first
	 * parameter of the advice method must be of type ProceedingJoinPoint.
	 * Within the body of the advice, calling proceed() on the
	 * ProceedingJoinPoint causes the underlying method to execute. The proceed
	 * method may also be called passing in an Object[] - the values in the
	 * array will be used as the arguments to the method execution when it
	 * proceeds.
	 */
	@Around("execution(* *..dao.*.*Logout(..))")
	public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
		// start stopwatch
		StringBuilder sbuilder = new StringBuilder();
		sbuilder.append("securityDao Around Advice log:\n");
		sbuilder.append("The proxy object: " + pjp.getThis() + "\n");
		sbuilder.append("The target object: " + pjp.getTarget() + "\n");
		sbuilder.append("The args: " + pjp.getArgs() + "\n");
		sbuilder.append("The signature: " + pjp.getSignature() + "\n");
		log.info(sbuilder.toString());
		Object retVal = pjp.proceed();
		sbuilder = new StringBuilder();
		sbuilder.append("securityDao Around Advice log:" + pjp.getSignature() +" done!\n");
		log.info(sbuilder.toString());
		// stop stopwatch
		return retVal;
	}
}